package wxpay

import (
	"errors"
	"fmt"
	"github.com/gogap/logs"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"strconv"
	"time"
	"yundian/internel/app/models/paysetting"
	"yundian/internel/pkg/dingo/global"
	"yundian/internel/pkg/utils"
	"yundian/internel/pkg/wxpay/wxcrypto"
)

// ------------payApi(支付api) - 支付API模块 -----------------//

// 微信小程序登录
func (pc *PayClient) Login(jscode, appId, appSecret string) (*PayData, error) {
	loginUrl := "https://api.weixin.qq.com/sns/jscode2session?appid=" + url.QueryEscape(appId) +
		"&secret=" + url.QueryEscape(appSecret) +
		"&js_code=" + url.QueryEscape(jscode) +
		"&grant_type=authorization_code"

	httpResp, err := pc.httpClient.Get(loginUrl)
	if err != nil {
		return nil, err
	}
	defer httpResp.Body.Close()

	if httpResp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("http.Status: %s", httpResp.Status)
	}

	respData := NewPayData()
	err = respData.FromJson(httpResp.Body)
	if err != nil {
		return nil, err
	}

	return respData, nil
}

// 统一下单 文档：https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=9_1&index=1
func ApiUnifiedOrder(payClient *PayClient, payData *PayData, wc *paysetting.PaySetting) (*PayData, error) {

	if !payData.IsSet("out_trade_no") ||
		!payData.IsSet("body") ||
		!payData.IsSet("total_fee") ||
		!payData.IsSet("trade_type") ||
		!payData.IsSet("notify_url") ||
		!payData.IsSet("spbill_create_ip") {
		return nil, fmt.Errorf("need pay param")
	}

	if payData.Get("trade_type") == TradeTypeJsApi && !payData.IsSet("openid") {
		return nil, fmt.Errorf("need openid")
	}

	if payData.Get("trade_type") == TradeTypeNative && !payData.IsSet("product_id") {
		return nil, fmt.Errorf("need product_id")
	}

	payData.Set("appid", wc.AppId)
	payData.Set("mch_id", wc.MchId)
	payData.Set("sign_type", SignTypeMD5)
	payData.Set("sign", payData.MakeSign(wc.ApiKey, SignTypeMD5))

	rpayData, err := payClient.PostXML(wxUrlUnifiedOrder, payData, wc.ApiKey)
	if err != nil {
		return nil, err
	}

	return rpayData, nil
}

// 查询订单
func ApiOrderQuery(payClient *PayClient, payData *PayData, wc *paysetting.PaySetting) (*PayData, error) {

	if !payData.IsSet("out_trade_no") &&
		!payData.IsSet("transaction_id") {
		return nil, fmt.Errorf("need pay param")
	}

	payData.Set("appid", wc.AppId)
	payData.Set("mch_id", wc.MchId)
	payData.Set("nonce_str", NonceStr())
	payData.Set("sign_type", SignTypeHMACSHA256)
	payData.Set("sign", payData.MakeSign(wc.ApiKey, SignTypeHMACSHA256))
	rpayData, err := payClient.PostXMLNoCheckSign(wxUrlOrderQuery, payData)
	if err != nil {
		log.Println(err.Error())
		return nil, err
	}
	return rpayData, nil
}

// 提交付款码支付
func ApiMicropay(payClient *PayClient, payData *PayData, wc *paysetting.PaySetting) (*PayData, error) {

	if !payData.IsSet("out_trade_no") ||
		!payData.IsSet("body") ||
		!payData.IsSet("total_fee") ||
		!payData.IsSet("auth_code") ||
		!payData.IsSet("spbill_create_ip") {
		return nil, fmt.Errorf("need pay param")
	}

	payData.Set("appid", wc.AppId)
	payData.Set("mch_id", wc.MchId)
	payData.Set("nonce_str", NonceStr())
	payData.Set("sign_type", SignTypeHMACSHA256)
	payData.Set("sign", payData.MakeSign(wc.ApiKey, SignTypeHMACSHA256))

	rpayData, err := payClient.PostXML(wxUrlMicropay, payData, wc.ApiKey)
	if err != nil {
		return nil, err
	}

	return rpayData, nil
}

// 关闭订单
func ApiCloseOrder(payClient *PayClient, payData *PayData, wc *paysetting.PaySetting) (*PayData, error) {

	if !payData.IsSet("out_trade_no") {
		return nil, fmt.Errorf("need pay param")
	}

	payData.Set("appid", wc.AppId)
	payData.Set("mch_id", wc.MchId)
	payData.Set("nonce_str", NonceStr())
	payData.Set("sign_type", SignTypeHMACSHA256)
	payData.Set("sign", payData.MakeSign(wc.ApiKey, SignTypeHMACSHA256))

	rpayData, err := payClient.PostXML(wxUrlCloseOrder, payData, wc.ApiKey)
	if err != nil {
		return nil, err
	}

	return rpayData, nil
}

// 申请退款 文档：https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=9_4
func ApiRefund(payClient *PayClient, payData *PayData, wc *paysetting.PaySetting) (*PayData, error) {
	if !payData.IsSet("transaction_id") ||
		!payData.IsSet("out_refund_no") ||
		!payData.IsSet("total_fee") ||
		!payData.IsSet("refund_fee") {
		return nil, fmt.Errorf("need pay param")
	}
	payData.Set("appid", wc.AppId)
	payData.Set("mch_id", wc.MchId)
	payData.Set("nonce_str", NonceStr())
	payData.Set("sign_type", SignTypeHMACSHA256)
	payData.Set("sign", payData.MakeSign(wc.ApiKey, SignTypeHMACSHA256))
	rpayData, err := payClient.PostXMLNoCheckSign(wxUrlRefund, payData)
	if err != nil {
		return nil, err
	}

	return rpayData, nil
}

// 撤销订单
func ApiReverse(payClient *PayClient, payData *PayData, wc *paysetting.PaySetting) (*PayData, error) {

	if !payData.IsSet("out_trade_no") {
		return nil, fmt.Errorf("need pay param")
	}

	payData.Set("appid", wc.AppId)
	payData.Set("mch_id", wc.MchId)
	payData.Set("nonce_str", NonceStr())
	payData.Set("sign_type", SignTypeHMACSHA256)
	payData.Set("sign", payData.MakeSign(wc.ApiKey, SignTypeHMACSHA256))

	rpayData, err := payClient.PostXML(wxUrlReverse, payData, wc.ApiKey)
	if err != nil {
		return nil, err
	}

	return rpayData, nil
}

// 查询退款
func ApiRefundQuery(payClient *PayClient, payData *PayData, wc *paysetting.PaySetting) (*PayData, error) {

	if !payData.IsSet("out_trade_no") &&
		!payData.IsSet("out_refund_no") &&
		!payData.IsSet("transaction_id") &&
		!payData.IsSet("refund_id") {
		return nil, fmt.Errorf("need pay param")
	}

	payData.Set("appid", wc.AppId)
	payData.Set("mch_id", wc.MchId)
	payData.Set("nonce_str", NonceStr())
	payData.Set("sign_type", SignTypeHMACSHA256)
	payData.Set("sign", payData.MakeSign(wc.ApiKey, SignTypeHMACSHA256))

	rpayData, err := payClient.PostXML(wxUrlRefundQuery, payData, wc.ApiKey)
	if err != nil {
		return nil, err
	}

	return rpayData, nil
}

// 下载对账单
func ApiDownloadBill(payClient *PayClient, payData *PayData, wc *paysetting.PaySetting) (*PayData, error) {

	if !payData.IsSet("bill_date") {
		return nil, fmt.Errorf("need pay param")
	}

	payData.Set("appid", wc.AppId)
	payData.Set("mch_id", wc.MchId)
	payData.Set("nonce_str", NonceStr())
	payData.Set("sign_type", SignTypeHMACSHA256)
	payData.Set("sign", payData.MakeSign(wc.ApiKey, SignTypeHMACSHA256))

	rpayData, err := payClient.PostXML(wxUrlDownloadBill, payData, wc.ApiKey)
	if err != nil {
		return nil, err
	}

	return rpayData, nil
}

// 创建支付分订单  文档： https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/payscore/chapter3_1.shtml
func ApiPayScoreOrder(payClient *PayClient, body []byte, wc *paysetting.PaySetting) (*PayData, error) {
	// 认证类型
	schema := "WECHATPAY2-SHA256-RSA2048"
	// 签名信息
	nonceStr := NonceStr()                            // 随机字符串
	timestamp := strconv.Itoa(int(time.Now().Unix())) // 时间戳timestamp
	signContent := utils.Join("POST\n", "/v3/payscore/serviceorder\n", timestamp, "\n", nonceStr, "\n", string(body), "\n")
	//block, _ := ioutil.ReadFile("./configs/zmwl/apiclient_key.pem") //私密证书key
	block, _ := ioutil.ReadFile(wc.ApiclientKeyPath) //私密证书key
	signature, _ := wxcrypto.RsaWithSHA256Base64(signContent, block) // 签名
	sign := utils.Join(
		"mchid=", SpliceString(wc.MchId), // 商户号mchid
		",serial_no=", SpliceString(wc.SerialNo), // 商户API证书序列号serial_no
		",nonce_str=", SpliceString(nonceStr),
		",signature=", SpliceString(signature),
		",timestamp=", SpliceString(timestamp))
	token := utils.Join(schema, " ", sign)

	rpayData, err := payClient.PostJson(wxPayScoreOrder, body, token)
	if err != nil {
		return nil, err
	}
	return rpayData, nil
}

// 发放小程序红包
func ApiSendminiprogramhb(payClient *PayClient, payData *PayData, wxConfig *paysetting.PaySetting) (*PayData, error) {
	if !payData.IsSet("re_openid") ||
		!payData.IsSet("mch_billno") ||
		!payData.IsSet("send_name") ||
		!payData.IsSet("total_amount") {
		return nil, fmt.Errorf("need pay param")
	}

	payData.Set("wxappid", wxConfig.AppId)
	payData.Set("mch_id", wxConfig.MchId)
	payData.Set("nonce_str", NonceStr())
	//payData.Set("sign", payData.MakeSign(WxPayConfig.ApiKey(), SignTypeMD5))
	payData.Set("sign", payData.MakeSign(wxConfig.ApiKey, SignTypeMD5))

	rpayData, err := payClient.PostXMLNoCheckSign(wxUrlSendminiprogramhb, payData)
	if err != nil {
		return rpayData, err
	}

	logs.Info(rpayData.ToJson())
	if rpayData.Get("result_code") == "FAIL" {
		return rpayData, errors.New(rpayData.Get("return_msg"))
		logs.Error("ApiSendminiprogramhb", rpayData.Get("return_msg"))
	}

	return rpayData, nil
}

// 发放红包
func ApiSendredpack(payClient *PayClient, payData *PayData) (*PayData, error) {
	if !payData.IsSet("re_openid") ||
		!payData.IsSet("mch_billno") ||
		!payData.IsSet("send_name") ||
		!payData.IsSet("total_amount") {
		return nil, fmt.Errorf("need pay param")
	}

	payData.Set("wxappid", global.Cfg.Wx.AppId)
	payData.Set("mchid", "1609227063")
	payData.Set("nonce_str", NonceStr())
	//payData.Set("sign", payData.MakeSign(WxPayConfig.ApiKey(), SignTypeMD5))
	payData.Set("sign", payData.MakeSign("wuxiangyunlianwuxiangyunlian3252", SignTypeMD5))

	rpayData, err := payClient.PostXMLNoCheckSign(wxUrlSendredpack, payData)
	if err != nil {
		return nil, err
	}

	return rpayData, nil
}

// 企业支付到零钱
func ApiTransfer(payClient *PayClient, payData *PayData, appid, mchid, apiKey string) (*PayData, error) {
	if !payData.IsSet("openid") ||
		!payData.IsSet("amount") ||
		!payData.IsSet("partner_trade_no") {
		return nil, fmt.Errorf("need pay param")
	}

	payData.Set("mch_appid", appid)
	payData.Set("mchid", mchid)
	payData.Set("nonce_str", NonceStr())
	//payData.Set("sign", payData.MakeSign(WxPayConfig.ApiKey(), SignTypeMD5))
	payData.Set("sign", payData.MakeSign(apiKey, SignTypeMD5))

	rpayData, err := payClient.PostXMLNoCheckSign(wxUrlTransfers, payData)
	if err != nil {
		return nil, err
	}

	return rpayData, nil
}

// 查询提现 - 国曼科技
func ApiQueryTransfer(payClient *PayClient, payData *PayData, appid, mchid, apiKey string) (*PayData, error) {
	if !payData.IsSet("partner_trade_no") {
		return nil, fmt.Errorf("need pay param")
	}

	payData.Set("appid", appid)
	//payData.Set("mch_id", WxPayConfig.MchId())
	payData.Set("mch_id", mchid)
	payData.Set("nonce_str", NonceStr())
	//payData.Set("sign", payData.MakeSign(WxPayConfig.ApiKey(), SignTypeMD5))
	payData.Set("sign", payData.MakeSign(apiKey, SignTypeMD5))
	rpayData, err := payClient.PostXMLNoCheckSign(wxUrlQueryTransfers, payData)
	if err != nil {
		return nil, err
	}

	return rpayData, nil
}

// 企业支付到零钱
func ApiTransferByGM(payClient *PayClient, payData *PayData) (*PayData, error) {
	if !payData.IsSet("openid") ||
		!payData.IsSet("amount") ||
		!payData.IsSet("partner_trade_no") {
		return nil, fmt.Errorf("need pay param")
	}

	payData.Set("mch_appid", global.Cfg.Wx.AppId)
	payData.Set("mchid", "1600369044")
	payData.Set("nonce_str", NonceStr())
	payData.Set("sign", payData.MakeSign("1D6ABC370832B6BC4A204AA5E78DAC8C", SignTypeMD5))
	rpayData, err := payClient.PostXMLNoCheckSign(wxUrlTransfers, payData)
	if err != nil {
		return nil, err
	}

	return rpayData, nil
}

// 查询提现
func ApiQueryTransferByGM(payClient *PayClient, payData *PayData) (*PayData, error) {
	if !payData.IsSet("partner_trade_no") {
		return nil, fmt.Errorf("need pay param")
	}

	payData.Set("appid", global.Cfg.Wx.AppId)
	payData.Set("mch_id", "1600369044")
	payData.Set("nonce_str", NonceStr())
	payData.Set("sign", payData.MakeSign("1D6ABC370832B6BC4A204AA5E78DAC8C", SignTypeMD5))
	rpayData, err := payClient.PostXMLNoCheckSign(wxUrlQueryTransfers, payData)
	if err != nil {
		return nil, err
	}

	return rpayData, nil
}

// 中曼速充商家号
func ZmApiTransfer(payClient *PayClient, payData *PayData, appid string) (*PayData, error) {
	if !payData.IsSet("openid") ||
		!payData.IsSet("amount") ||
		!payData.IsSet("partner_trade_no") {
		return nil, fmt.Errorf("need pay param")
	}

	payData.Set("mch_appid", appid)
	payData.Set("mchid", "1604377294")
	payData.Set("nonce_str", NonceStr())
	//payData.Set("sign", payData.MakeSign(WxPayConfig.ApiKey(), SignTypeMD5))
	payData.Set("sign", payData.MakeSign("166966ACD2FD9DD0BCD090C4E26D5AF1", SignTypeMD5))

	rpayData, err := payClient.PostXMLNoCheckSign(wxUrlTransfers, payData)
	if err != nil {
		return nil, err
	}

	return rpayData, nil
}

func ApiQueryTransferByZm(payClient *PayClient, payData *PayData, appid string) (*PayData, error) {
	if !payData.IsSet("partner_trade_no") {
		return nil, fmt.Errorf("need pay param")
	}

	payData.Set("appid", appid)
	//payData.Set("mch_id", WxPayConfig.MchId())
	payData.Set("mch_id", "1604377294")
	payData.Set("nonce_str", NonceStr())
	//payData.Set("sign", payData.MakeSign(WxPayConfig.ApiKey(), SignTypeMD5))
	payData.Set("sign", payData.MakeSign("166966ACD2FD9DD0BCD090C4E26D5AF1", SignTypeMD5))
	rpayData, err := payClient.PostXMLNoCheckSign(wxUrlQueryTransfers, payData)
	if err != nil {
		return nil, err
	}

	return rpayData, nil
}
